from absl import app, flags
import datetime
import pandas as pd

import coin.base.database.util as db_util
from coin.support.accounting.app.report_estimate import formatNumber
from coin.support.accounting.logic.mysql_querier import \
  MysqlCoinInfoQuerier as MysqlInfoQuerier
from xunkemgmt.support.accounting.logic.query_request import (
    filter_invalid_request_and_result,
    get_kline_requests,
)

FLAGS = flags.FLAGS

coinmarketcap_period_map = {1: '1d', 7: '1W', 30: '1M'}


def _parse_kline_timestamp(kline_timestamp, request):
  kline_trading_date = datetime.datetime.utcfromtimestamp(kline_timestamp / 1e+9).date()
  if request.market_type == 'Info':
    daydelta = {v: k for k, v in coinmarketcap_period_map.items()}[request.kline_period]
    kline_trading_date += datetime.timedelta(days=daydelta - 1)
  return kline_trading_date


def sum_symbol_volume(market_type, symbol_volume_df, trading_date, volume_period):
  assert symbol_volume_df['trading_date'].iloc[-1] == trading_date, \
    ("Missing data in %s" % trading_date)
  symbol_volume_df = symbol_volume_df[symbol_volume_df['kline_timestamp'] != 0]
  start_date = trading_date - datetime.timedelta(days=volume_period - 1)
  assert len(symbol_volume_df) == volume_period, \
    ("Missing data before %s" % trading_date)
  assert symbol_volume_df['trading_date'].iloc[0] == start_date, \
    ("Missing data in %s" % start_date)
  return symbol_volume_df['symbol_volume'].sum()


def print_daily_volume(kline_request_list, start_date, end_date, volume_print_period):
  db_config = db_util.read_db_config(FLAGS.mysql_config)
  querier = MysqlInfoQuerier(db_config)
  start_date_query = (start_date - datetime.timedelta(days=max(volume_print_period) - 1))
  kline_response_list = querier.query_kline_history(kline_request_list, start_date_query, end_date)
  kline_request_list, kline_response_list = \
    filter_invalid_request_and_result(kline_request_list, kline_response_list)
  daily_volume_list = []
  for request, response in zip(kline_request_list, kline_response_list):
    symbol_volume_list = []
    for kline in response.klines.klines:
      if request.symbol_contract_type == 'TOTAL':
        symbol_volume_list.append([
            request.market_type,
            request.exchange,
            request.symbol_contract_type,
            request.kline_period,
            kline.kline_timestamp,
            kline.turnover_in_usd
        ])
      else:
        symbol_volume_list.append([
            request.market_type,
            request.exchange,
            request.symbol_contract_type,
            request.kline_period,
            kline.kline_timestamp,
            kline.volume
        ])
    symbol_volume_df = pd.DataFrame(symbol_volume_list,
                                    columns=[
                                        'market_type',
                                        'exchange',
                                        'symbol',
                                        'kline_period',
                                        'kline_timestamp',
                                        'symbol_volume'
                                    ])
    symbol_volume_df['trading_date'] = \
      symbol_volume_df['kline_timestamp'].apply(_parse_kline_timestamp,
                                                request=request)
    symbol_volume_df.sort_values('trading_date', inplace=True)
    for trading_datetime in pd.date_range(start_date, end_date):
      trading_date = trading_datetime.date()
      for volume_period in volume_print_period:
        symbol_volume_before = symbol_volume_df[(symbol_volume_df['trading_date'] <=
                                                 trading_date)][-volume_period:]
        try:
          volume = sum_symbol_volume(request.market_type,
                                     symbol_volume_before,
                                     trading_date,
                                     volume_period)
        except Exception as e:
          print(type(e), e, request)
          volume = None
        daily_volume_list.append([
            trading_date,
            request.market_type,
            request.exchange,
            request.symbol_contract_type,
            'volume(%sday)' % volume_period,
            volume
        ])
  daily_volume = pd.DataFrame(
      daily_volume_list,
      columns=['trading_date', 'market_type', 'exchange', 'symbol', 'volume_period', 'volume'])
  daily_volume.dropna(inplace=True)
  daily_volume = daily_volume.pivot_table(
      index=['trading_date', 'market_type', 'exchange', 'symbol'],
      columns=['volume_period'],
      values=['volume'])
  daily_volume = daily_volume.reset_index().T.reset_index().T
  daily_volume_columns = (daily_volume.loc['level_0'].iloc[:4].tolist()
                          + daily_volume.loc['volume_period'].iloc[4:].tolist())
  daily_volume = daily_volume.iloc[2:]
  daily_volume.columns = daily_volume_columns
  for trading_datetime in pd.date_range(start_date, end_date):
    trading_date = trading_datetime.date()
    display_df = daily_volume[daily_volume['trading_date'] == trading_date]
    for volume_period in volume_print_period:
      col = 'volume(%sday)' % volume_period
      if col in display_df.columns:
        display_df[col] = display_df[col].apply(formatNumber)
      else:
        display_df[col] = ''
    display_df_columns = (['market_type', 'exchange', 'symbol']
                          + ['volume(%sday)' % i for i in volume_print_period])
    print(display_df.set_index('trading_date').to_string(columns=display_df_columns))
    print('\n')


def main(_):
  pd.set_option('display.max_columns', None)
  pd.set_option('display.width', 200)
  pd.set_option('max_colwidth', 200)
  if FLAGS.start_date is None:
    start_date = datetime.datetime.utcnow().date() - datetime.timedelta(days=1)
  else:
    start_date = datetime.datetime.strptime(FLAGS.start_date, '%Y%m%d').date()
  if FLAGS.end_date is None:
    end_date = datetime.datetime.utcnow().date() - datetime.timedelta(days=1)
  else:
    end_date = datetime.datetime.strptime(FLAGS.end_date, '%Y%m%d').date()
  assert start_date <= end_date < datetime.datetime.utcnow().date(), \
    (start_date, end_date, datetime.datetime.utcnow().date())
  volume_print_period = FLAGS.volume_print_period
  volume_print_period = volume_print_period.split(',')
  volume_print_period = [int(x) for x in volume_print_period]
  kline_request_list = get_kline_requests(None, FLAGS.kline_symbols_list)
  print_daily_volume(kline_request_list, start_date, end_date, volume_print_period)


if __name__ == '__main__':
  flags.DEFINE_string('volume_print_period', '1,7,30', 'volume_print_period')
  flags.DEFINE_string(
      'kline_symbols_list',
      '../../coin_deploy/support_accounting/kline_config/volume_print_symbols_list.csv',
      'kline_symbols_list')
  flags.DEFINE_string('start_date', None, '%Y%m%d')
  flags.DEFINE_string('end_date', None, '%Y%m%d')
  flags.DEFINE_string('mysql_config', None, 'path of database config.')
  app.run(main)
